import requests
import os
import re
from urllib.parse import urlparse
import tkinter as tk
from tkinter import filedialog


def clean_text(text):
    """
    清理文本：去除多余的空格、换行符、空行等
    """
    # 替换多个连续换行符为单个句号（模拟段落结束）
    text = re.sub(r'\n+', '。', text)
    
    # 替换多个连续空格为单个空格
    text = re.sub(r' +', ' ', text)
    
    # 去除首尾空白字符
    text = text.strip()
    
    # 确保文本以句号结束（如果不是以标点符号结束）
    if text and text[-1] not in ['。', '！', '？', '.', '!', '?']:
        text += '。'
    
    return text


def split_text_by_sentences(text, max_length=100):
    """
    按句号分割文本，尽量保证每段不超过 max_length
    """
    if len(text) <= max_length:
        return [text]

    segments = []
    current_segment = ""

    # 按句号分割句子
    sentences = text.split("。")
    # 补回句号（除了最后一句可能无句号）
    sentences = [
        s + "。" if i < len(sentences) - 1 else s for i, s in enumerate(sentences)
    ]

    for sentence in sentences:
        # 如果当前段 + 新句子超过限制，且当前段非空，则保存当前段
        if len(current_segment) + len(sentence) > max_length and current_segment:
            segments.append(current_segment)
            current_segment = sentence
        else:
            current_segment += sentence

    # 添加最后一段
    if current_segment:
        segments.append(current_segment)

    return segments


def text_to_speech(text, output_dir=".", filename=None, segment_index=None):
    """
    将文本转换为语音并保存为音频文件

    参数:
        text (str): 要转换的文本内容
        output_dir (str): 音频文件保存目录，默认为当前目录
        filename (str): 自定义文件名（不含扩展名），如未指定则使用API返回的文件名
        segment_index (int): 分段序号，用于自动命名多个文件

    返回:
        str: 保存的音频文件完整路径，失败返回 None
    """
    # API端点
    # url = "http://127.0.0.1:9966/tts"
    url = "http://192.168.0.198:9966/tts"  # 可选备用地址

    # 请求参数
    payload = {
        "text": text,
        "prompt": "[break_6]",
        "voice": "7777.pt",
        "speed": 5,
        "temperature": 0.1,
        "top_p": 0.701,
        "top_k": 20,
        "refine_max_new_token": 384,
        "infer_max_new_token": 2048,
        "text_seed": 42,
        "skip_refine": 1,
        "is_stream": 0,
        "custom_voice": 0,
    }

    try:
        # 发送POST请求
        response = requests.post(url, data=payload)
        response.raise_for_status()

        # 解析响应JSON
        result = response.json()

        # 检查API返回状态
        if result.get("code") != 0:
            raise Exception(f"API错误: {result.get('msg', '未知错误')}")

        # 获取音频文件信息
        audio_info = result["audio_files"][0]
        audio_url = audio_info["url"]

        # 确定保存文件名
        if filename:
            base_name = f"{filename}"
            if segment_index is not None:
                base_name += f"_{segment_index:03d}"
            base_name += ".wav"
        else:
            parsed_url = urlparse(audio_url)
            base_name = os.path.basename(parsed_url.path)
            if segment_index is not None:
                name, ext = os.path.splitext(base_name)
                base_name = f"{name}_{segment_index:03d}{ext}"

        # 确保输出目录存在
        os.makedirs(output_dir, exist_ok=True)
        save_path = os.path.join(output_dir, base_name)

        # 下载音频文件
        audio_response = requests.get(audio_url)
        audio_response.raise_for_status()

        # 保存到本地
        with open(save_path, "wb") as f:
            f.write(audio_response.content)

        print(f"✅ 音频文件已保存至: {save_path}")
        return save_path

    except requests.exceptions.RequestException as e:
        print(f"❌ 请求失败: {str(e)}")
    except Exception as e:
        print(f"❌ 处理失败: {str(e)}")
    return None


def select_and_process_text_file():
    """
    弹出文件选择对话框，选择文本文件，读取内容并分段合成语音
    """
    # 初始化Tkinter（隐藏主窗口）
    root = tk.Tk()
    root.withdraw()  # 隐藏主窗口

    # 打开文件选择对话框
    file_path = filedialog.askopenfilename(
        title="选择要合成语音的文本文件",
        filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
    )

    if not file_path:
        print("⚠️ 未选择文件，程序退出。")
        return

    print(f"📄 正在读取文件: {file_path}")

    # 读取文件内容（假设为 UTF-8 编码）
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            content = f.read().strip()
    except Exception as e:
        print(f"❌ 读取文件失败: {str(e)}")
        return

    if not content:
        print("⚠️ 文件内容为空。")
        return

    # 清理文本：去除换行符、空行等
    original_length = len(content)
    content = clean_text(content)
    cleaned_length = len(content)
    print(f"🧹 文本清理完成: {original_length} → {cleaned_length} 字符")

    # 获取原始文件名（不含路径和扩展名）用于命名输出文件
    base_filename = os.path.splitext(os.path.basename(file_path))[0]

    # 输出目录：在原文件同目录下创建 "audio_output" 文件夹
    output_dir = os.path.join(os.path.dirname(file_path), "audio_output")

    # 分割文本
    segments = split_text_by_sentences(content, max_length=2000)
    print(f"✂️  文本被分割为 {len(segments)} 段进行合成。")

    # 逐段合成
    saved_files = []
    for i, segment in enumerate(segments, start=1):
        print(f"\n🔊 正在合成第 {i}/{len(segments)} 段，长度: {len(segment)} 字符...")
        saved_file = text_to_speech(
            text=segment, output_dir=output_dir, filename=base_filename, segment_index=i
        )
        if saved_file:
            saved_files.append(saved_file)

    # 总结
    if saved_files:
        print(f"\n🎉 全部合成完成！共生成 {len(saved_files)} 个音频文件。")
        print(f"📁 输出目录: {output_dir}")
    else:
        print("❌ 未成功生成任何音频文件。")


# 使用示例
if __name__ == "__main__":
    select_and_process_text_file()